package {{.packageName}}

import (
	"database/sql"
	"fmt"
	"log"
	"reflect"
	"strings"
)

type (
	{{.modelName}}Repo struct {
		db      *sql.DB
		OpenLog bool
	}
)

func (w *{{.modelName}}Repo) QueryById(input *{{.modelName}}) (u *{{.modelName}}, err error) {
	var db = w.db
	var sql = "select {{.selectFields}} from {{.tableName}}  where  {{.tableId}} = ?"
	stmt, err := db.Prepare(sql)
	if err != nil {
		return u, err
	}

	defer stmt.Close()
	if w.OpenLog {
		log.Println("sql = ", sql)
		log.Println("params = ", input.{{.tableIdProp}})
	}
	row := stmt.QueryRow(input.{{.tableIdProp}})

	u = &{{.modelName}}{}
	_ = row.Scan({{.scanFields}})

	return u, err
}

func (w *{{.modelName}}Repo) QueryAll() (res []*{{.modelName}}, err error) {
	var db = w.db
	//qq := &{{.modelName}}{}
	var sql = "select {{.selectFields}}  from {{.tableName}} "

	stmt, err := db.Prepare(sql)
	if err != nil {
		return res, err
	}
	defer stmt.Close()
	if w.OpenLog {
		log.Println("sql = ", sql)
		//log.Println("params = ",)
	}

	rows, err := stmt.Query()
	if err != nil {
		return res, err
	}
	defer rows.Close()

	for rows.Next() {
		var u {{.modelName}}
		_ = rows.Scan({{.scanFields}})
		res = append(res, &u)
	}
	return res, err
}

func (w *{{.modelName}}Repo) DeleteById(input *{{.modelName}}) (sql.Result, error) {
	var db = w.db
	var sql = "delete from {{.tableName}}  where {{.tableId}}= ?"
	if w.OpenLog {
		log.Println(sql)
	}
	stmt, err := db.Prepare(sql)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	exec, err := stmt.Exec(input.{{.tableIdProp}} )
	return exec, err
}
func (w *{{.modelName}}Repo) UpdateById(u *{{.modelName}}) (sql.Result, error) {
	var db = w.db
	var x = "update {{.tableName}}   set {{.setFields}}  where {{.tableId}} = ?"
	if w.OpenLog {
		log.Println(x)
	}
	stmt, err := db.Prepare(x)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	exec, err := stmt.Exec(u.{{.tableIdProp}})
	return exec, err
}
func (w *{{.modelName}}Repo) UpdateOmitZeroValue(u *{{.modelName}}, where string, args ...interface{}) (sql.Result, error) {
	var db = w.db
	var sql strings.Builder
	sql.WriteString("update {{.tableName}}  set ")
	var setCnt int
	rvalue := reflect.Indirect(reflect.ValueOf(u))
	valueType := reflect.TypeOf(u)
	var params []interface{}
	for i := 0; i < rvalue.NumField(); i++ {
		var cur = rvalue.Field(i)
		if cur.IsValid() && cur.IsZero() == false {
			setCnt++
			field := valueType.Elem().Field(i)
			var name = field.Tag.Get("db")
			if name == "" {
				name = field.Name
			}
			sql.WriteString(fmt.Sprintf("%s = ?", name))
			params = append(params, cur.Interface())
		}
	}
	if setCnt == 0 {
		return nil, nil
	}
	sql.WriteString(" where ")
	sql.WriteString(where)
	params = append(params, args...)
	if w.OpenLog {
		fmt.Println(sql.String())
		fmt.Println(params)

	}

	stmt, err := db.Prepare(sql.String())
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	if w.OpenLog {
		log.Println("sql = ", sql)
		log.Println("params = ", u)
	}
	return stmt.Exec(params...)

}

func (w *{{.modelName}}Repo) Insert(u *{{.modelName}}) (sql.Result, error) {
	var db = w.db
	var sql = "insert into {{.tableName}}  ({{.selectFields}}) values ({{.questionFields}})"
	if w.OpenLog {
		log.Println("sql = ", sql)
		log.Println("params = ", u)
	}
	stmt, err := db.Prepare(sql)
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	return stmt.Exec({{.scanFields}})

}

func (w *{{.modelName}}Repo) InsertSelective(u *{{.modelName}}) (sql.Result, error) {
	//var db = w.db
	var sqlCmd = strings.Builder{}
	sqlCmd.WriteString("insert into {{.tableName}} (")
	var setCnt int
	rvalue := reflect.Indirect(reflect.ValueOf(u))
	valueType := reflect.TypeOf(u)
	var params []interface{}
	for i := 0; i < rvalue.NumField(); i++ {
		var cur = rvalue.Field(i)
		if cur.IsValid() && cur.IsZero() == false {
			if setCnt > 0 {
				sqlCmd.WriteString(",")
			}
			setCnt++
			field := valueType.Elem().Field(i)
			var name = field.Tag.Get("db")
			if name == "" {
				name = field.Name
			}

			sqlCmd.WriteString(fmt.Sprintf("%s", name))
			params = append(params, cur.Interface())
		}
	}

	if setCnt == 0 {
		return nil, nil
	}
	sqlCmd.WriteString(")")
	sqlCmd.WriteString(" values (")
	for i := 0; i < setCnt; i++ {
		if i > 0 && i < setCnt {
			sqlCmd.WriteString(",")
		}
		sqlCmd.WriteString("?")

	}
	sqlCmd.WriteString(") ")

	if w.OpenLog {
		log.Println("sqlCmd = ", sqlCmd.String())
		log.Printf("params = %+v\n", u)
	}
	var db = w.db
	stmt, err := db.Prepare(sqlCmd.String())
	if err != nil {
		return nil, err
	}
	defer stmt.Close()
	return stmt.Exec(params...)

}
func (w *{{.modelName}}Repo) QueryCallback(sqlStr string, callback func(rows *sql.Rows) (*{{.modelName}}, error), args ...interface{}) (res []*{{.modelName}}, err error) {
	var db = w.db
	stmt, err := db.Prepare(sqlStr)
	if err != nil {
		return res, err
	}
	defer stmt.Close()
	if w.OpenLog {
		log.Println("sql = ", sqlStr)
		log.Println("params = ", args)
	}
	//args0 := args
	rows, err := stmt.Query(args...)
	if err != nil {
		return res, err
	}
	defer rows.Close()
	for rows.Next() {
		{{.modelName}}, err := callback(rows)
		if err != nil {
			return res, err
		}
		res = append(res, {{.modelName}})
	}
	return res, err
}
func (w *{{.modelName}}Repo)  Exec(sqlcmd string ,args...interface{}) (sql.Result,error) {
	var db = w.db
	var stmt , err = db.Prepare(sqlcmd)
	if err != nil {
		return nil,err
	}
	defer stmt.Close()
	exec, err := stmt.Exec(args...)
	return exec,err
}


func (w *DeptRepo) Query(sqlCmd string,calback func(stmt *sql.Stmt) error ) (error) {
	stmt, err := w.db.Prepare(sqlCmd)
	if err != nil {
		return err
	}
	defer stmt.Close()
	err = calback(stmt)
	return err
}
